package com.pudding.ragdemo;

import com.pudding.tools.ModelUtil;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.rag.DefaultRetrievalAugmentor;
import dev.langchain4j.rag.content.injector.ContentInjector;
import dev.langchain4j.rag.content.injector.DefaultContentInjector;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.redis.RedisEmbeddingStore;

import java.time.LocalDateTime;

/**
 * 美团业务场景的RAG（检索增强生成）服务类
 * <p>
 * 该类实现了一个智能客服系统，结合了以下核心功能：
 * 1. RAG技术：从Redis向量数据库中检索相关业务知识
 * 2. 对话记忆：维护多轮对话的上下文
 * 3. 工具调用：支持调用外部工具（如日期计算）增强AI能力
 * 4. 语义检索：使用向量嵌入模型实现语义相似度匹配
 * <p>
 * 典型应用场景：基于美团业务知识库回答用户关于提现、退款等业务问题
 *
 * @author pudding
 */
public class MeituanRagService {
    
    /**
     * AI客服接口
     * <p>
     * 这是一个被AiServices代理的接口，LangChain4j框架会自动实现该接口，
     * 并将用户问题转换为对大语言模型的调用，同时自动触发RAG检索和工具调用
     */
    interface AiCustomer {
        /**
         * 回答用户问题
         *
         * @param question 用户提出的问题
         * @return AI生成的答案，可能包含从知识库检索到的信息和工具调用结果
         */
        String answer(String question);
    }

    /**
     * 创建并配置AI客服服务实例
     * <p>
     * 该方法按照以下步骤构建完整的RAG服务链路：
     * 1. 初始化OpenAI聊天模型作为核心推理引擎
     * 2. 初始化OpenAI嵌入模型用于文本向量化
     * 3. 配置Redis向量数据库用于存储和检索知识库
     * 4. 构建内容检索器，实现语义相似度搜索
     * 5. 配置内容注入器，将检索结果注入到提示词中
     * 6. 组装RAG增强器，整合检索和注入流程
     * 7. 配置对话记忆，支持多轮对话上下文
     * 8. 注册工具类，扩展AI的能力边界
     *
     * @return 配置完成的AiCustomer实例，可直接用于回答问题
     */
    public static AiCustomer create() {
        // 1. 构建聊天语言模型
        // 使用OpenAI的GPT模型作为对话生成的核心引擎
        ChatLanguageModel chatLanguageModel = OpenAiChatModel.builder()
                .apiKey(ModelUtil.API_KEY_OPENAI)
                .build();
        
        // 2. 构建文本嵌入模型
        // 用于将文本转换为向量，实现语义相似度计算
        // 使用的是OpenAI的text-embedding模型，生成1536维向量
        EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
                .baseUrl(ModelUtil.BASE_URL_OPENAI)
                .apiKey(ModelUtil.API_KEY_OPENAI)
                .build();
        
        // 3. 创建向量数据库存储
        // 使用Redis作为向量数据库，存储业务知识的向量表示
        // dimension=1536 对应OpenAI嵌入模型的输出维度
        EmbeddingStore<TextSegment> embeddingStore = RedisEmbeddingStore.builder()
                .host("127.0.0.1")
                .port(6379)
                .dimension(1536)  // 向量维度，需与嵌入模型输出维度一致
                .indexName("meituan-rag")  // Redis中的索引名称
                .build();
        
        // 4. 创建内容检索器
        // 负责根据用户问题从向量数据库中检索最相关的知识片段
        ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)  // 指定向量存储
                .embeddingModel(embeddingModel)  // 指定嵌入模型，用于将问题向量化
                .maxResults(5)  // 最多返回5个最相关的结果
                .minScore(0.8)  // 相似度阈值，只返回余弦相似度≥0.8的结果
                .build();
        
        // 5. 创建内容注入器
        // 负责将检索到的知识片段格式化后注入到发送给大模型的提示词中
        ContentInjector contentInjector = new DefaultContentInjector();
        
        // 6. 创建检索增强生成器（RAG核心组件）
        // 整合检索和注入流程，在每次对话前自动执行知识检索
        DefaultRetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
                .contentRetriever(contentRetriever)  // 指定检索器
                .contentInjector(contentInjector)    // 指定注入器
                .build();
        
        // 7. 创建对话记忆
        // 保存最近10轮对话，使AI能够理解上下文和指代关系
        ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
        
        // 8. 构建并返回AI服务实例
        // 将所有组件整合，创建一个功能完整的AI客服代理
        return AiServices.builder(AiCustomer.class)
                .chatLanguageModel(chatLanguageModel)      // 核心对话模型
                .retrievalAugmentor(retrievalAugmentor)    // RAG增强器
                .tools(new DataCalculator())                // 注册日期计算工具
                .chatMemory(chatMemory)                     // 对话记忆
                .build();
    }

    /**
     * 日期计算工具类
     * <p>
     * 作为LangChain4j的Tool，该类会被AI模型自动调用。
     * 当用户问题需要计算未来日期时（如"3天后是几号"），
     * 大模型会自主决定调用此工具，并将计算结果融入最终答案。
     * <p>
     * 工作原理：
     * 1. 大模型理解用户意图后，发现需要日期计算
     * 2. 自动调用date方法，传入计算的天数
     * 3. 获取计算结果后，将其整合到自然语言回复中
     * <p>
     * 应用场景：处理"余额提现3天到账，具体哪天到账？"这类问题
     */
    static class DataCalculator {
        /**
         * 计算从今天开始指定天数后的日期
         * 
         * @param days 天数，可以为正数（未来）或负数（过去）
         * @return 计算后的日期时间字符串，格式如：2025-11-05T14:30:00
         */
        @Tool("计算指定天数后的具体日期")
        String date(Integer days) {
            return LocalDateTime.now().plusDays(days).toString();
        }
    }

    /**
     * 主方法 - 演示RAG服务的使用
     * <p>
     * 演示场景：用户询问余额提现到账日期
     * 执行流程：
     * 1. 创建AI客服实例（包含RAG能力和日期工具）
     * 2. 用户提问："今天的余额提现，最晚哪天能到账？给我具体的日期"
     * 3. 系统自动从Redis检索到"余额提现3天到账"的业务规则
     * 4. AI调用DataCalculator工具计算3天后的具体日期
     * 5. 将检索结果和计算结果整合，生成完整答案
     *
     * @param args 命令行参数（未使用）
     */
    public static void main(String[] args) {
        // 创建配置好的AI客服服务实例
        AiCustomer aiCustomer = MeituanRagService.create();
        
        // 提出业务问题：询问余额提现的具体到账日期
        // AI会自动：1) 从知识库检索提现规则  2) 调用日期工具计算  3) 生成答案
        String result = aiCustomer.answer("今天的余额提现，最晚哪天能到账？给我具体的日期");
        
        // 输出AI的回答
        System.out.println(result);
    }
}
